// 16.事务.go
// 演示 GORM 框架中事务的使用方法
// 本文件包含多种事务处理方式的示例：
// 1. 全局禁用默认事务（SQLite为例）
// 2. 无事务保护的简单操作
// 3. 自动事务处理
// 4. 手动事务处理
package main

import (
	"gin-gorm/global" // 全局配置包，提供数据库连接等功能
	"gin-gorm/models"  // 模型定义包，包含UserModel等模型定义

	"gorm.io/gorm" // GORM核心包，提供数据库操作接口
)

// sqlite 函数演示如何在SQLite数据库中全局禁用默认事务
// 注意：此函数目前仅作为配置示例，实际代码被注释掉
func sqlite() {
	// 全局禁用默认事务的配置示例
	// 事务禁用的优缺点：
	// - 性能提升：约 30%+ 的性能提升（通过减少事务开销）
	// - 使用场景：对事务一致性要求不高的场景
	// - 注意事项：一般不推荐禁用（因为会失去事务的原子性保护）
	// db, err := gorm.Open(sqlite.Open("gorm.db"), &gorm.Config{
	//	SkipDefaultTransaction: true, // 禁用默认事务
	// })

	// 错误处理：如果数据库连接失败则抛出异常
	// if err != nil {
	//	panic("数据库连接失败")
	// }

	// // 使用配置好的数据库连接进行操作
	// fmt.Println(db)
}

// test 函数演示不同事务处理方式的实际应用
// 以张三给李四转账的场景为例，展示了事务的重要性
func test() {
	// 创建用户模型实例，仅设置ID用于后续操作
	var zhangsan = models.UserModel{ID: 1} // 转账方：张三
	var lisi = models.UserModel{ID: 2}     // 收款方：李四

	// 示例1：无事务保护的简单操作（当前被注释掉）
	// 注意：这种方式在并发环境下可能导致数据不一致
	// 例如：张三扣款成功但李四未收到款，或者张三未扣款但李四收到款
	// global.DB.Model(&zhangsan).Update("money", gorm.Expr("money - ?", 100)) // 张三扣款100元
	// global.DB.Model(&lisi).Update("money", gorm.Expr("money + ?", 100))     // 李四收款100元

	// 示例2：自动事务处理（当前被注释掉）
	// GORM的自动事务通过函数闭包实现，更加简洁易用
	// 当闭包返回非nil错误时，事务会自动回滚；返回nil时，事务会自动提交
	// 自动事务 ---------------------------------------
	// err := global.DB.Transaction(func(tx *gorm.DB) error {
	//	// 在事务中执行转账操作，使用tx而不是global.DB
	//	tx.Model(&zhangsan).Update("money", gorm.Expr("money - ?", 100)) // 张三扣款100元
	//	tx.Model(&lisi).Update("money", gorm.Expr("money + ?", 100))     // 李四收款100元

	//	// 返回nil表示操作成功，事务将自动提交
	//	return nil
	// })
	// fmt.Println(err) // 打印可能的错误信息
	// 自动事务 ---------------------------------------

	// 示例3：手动事务处理（当前实际运行的代码）
	// 手动事务提供了更细粒度的控制，可以根据具体情况决定何时提交或回滚
	// 手动 事务 ---------------------------------------
	tx := global.DB.Begin() // 开始事务，获取事务对象tx
	
	// 在事务中执行张三扣款操作
	// 使用gorm.Expr实现SQL表达式，确保数据一致性
	err := tx.Model(&zhangsan).Update("money", gorm.Expr("money - ?", 100))
	// 错误检查：如果扣款操作失败，则回滚事务并返回
	if err != nil {
		tx.Rollback() // 回滚事务，撤销所有已执行的操作
		return
	}
	
	// 被注释掉的重复代码（可能是调试遗留）
	// tx.Model(&zhangsan).Update("money", gorm.Expr("money - ?", 100))
	
	// 在事务中执行李四收款操作
	tx.Model(&lisi).Update("money", gorm.Expr("money + ?", 100))
	// 提交事务，使所有操作永久生效
	tx.Commit()
	// 手动 事务 ---------------------------------------

}

// main 函数是程序的入口点
// 负责初始化数据库连接并调用事务演示函数
func main() {
	// 连接数据库
	// 调用global包中的Connect函数建立数据库连接
	global.Connect()
	
	// 迁移数据库表结构（当前被注释掉）
	// global.Migrate()会根据模型定义自动创建或更新数据库表
	// global.Migrate()
	
	// 调用test函数执行事务演示
	test()
}
